﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using SignalR;
using System.Threading.Tasks;
using UnliQ.Service.Contracts;
using UnliQ.ServiceLayer;

namespace UnliQ.Web.Framework.UnliQSignalR
{
    public enum UnliQConnectType
    {
        Connect = 1,
        Disconnect = 2,
        Recieve = 3
    }

    public class UnliQServerResponse<T>
    {
        public string Type { get; set; }
        public T Model { get; set; }
        public bool Success { get; set; }
        public string Message { get; set; }
        public string ConnectionId { get; set; }
    }

    public struct ReserveModel
    {
        public string EventName { get; set; }
        public string CurrentQueueCount { get; set; }
        public string QueueNumber { get; set; }
    }

    public class UnliQConnection : PersistentConnection
    {
        private IQueueService _queueService;
        private IUserService _userService;
        public const string TEST_CONNECTION = "TEST_CONNECTION";
        public const string UPDATE_NOWSERVING = "UPDATE_NOWSERVING";
        public const string RESERVE_QUEUE = "RESERVE_QUEUE";

        #region [Private Method(s)]

        private Task ConnectionActivity(string connectionId, UnliQConnectType connectType)
        {
            //ConcurrentDictionary<string, object> stationlist = new ConcurrentDictionary<string, object>();
            var groupName = GetGroupName(connectionId);

            if (string.IsNullOrEmpty(groupName))
                return Connection.Send(connectionId, connectionId);

            Task result = null;

            switch (connectType)
            {
                case UnliQConnectType.Connect:
                    {
                        result = Groups.Add(connectionId, groupName);
                        break;
                    }
                case UnliQConnectType.Disconnect:
                    {
                        result = Groups.Remove(connectionId, groupName);
                        break;
                    }
                case UnliQConnectType.Recieve:
                    {
                        break;
                    }
            }

            return result;
        }

        private string GetGroupName(string connectionId)
        {
            //TODO : get groups by username/conectionId
            var group = "defaultGroup";
            //group = _queueService.
            return group;

        }


        private void DecodeMessage(string message, string connectionId)
        {
            string[] objMessage = message.Split(':');
            string type = objMessage[0];

            switch (type)
            {
                case TEST_CONNECTION:
                    {
                        Connection.Broadcast(new UnliQServerResponse<string>
                        {
                            ConnectionId = connectionId,
                            Message = "success",
                            Model = "test connection",
                            Success = true,
                            Type = TEST_CONNECTION
                        });
                        break;
                    }
                case UPDATE_NOWSERVING:
                    {
                        var group = GetGroupName(connectionId);

                        var nextResult = _queueService.NextQueue(objMessage[1]);


                        if (nextResult != null && nextResult.IsSuccessful)
                        {
                            this.Connection.Send(connectionId, new UnliQServerResponse<string>
                            {
                                ConnectionId = connectionId,
                                Type = UPDATE_NOWSERVING,
                                Model = objMessage[1],
                                Message = nextResult.ReturnModel.ToString()
                            });
                        }


                        break;
                    }
                case RESERVE_QUEUE:
                    {
                        var result = _userService.GetId(connectionId);
                        var eventName = objMessage[1];

                        if (result != null && result.ReturnModel != 0)
                        {
                            var resultQueueNumber = _queueService.AssignUserToQueue(result.ReturnModel, eventName);

                            var resultUsers = _queueService.GetUsersInEvent(eventName);
                            var resultUserNames = _userService.GetUsernames(resultUsers.ReturnModel);

                            if (resultQueueNumber != null && resultUserNames != null && resultUserNames.ReturnModel != null)
                            {

                                resultUserNames.ReturnModel.ForEach(e =>
                                {
                                    if (e != connectionId)
                                    {
                                        this.Connection.Send(e, new UnliQServerResponse<ReserveModel>
                                        {
                                            Model = new ReserveModel
                                             {
                                                 CurrentQueueCount = resultUserNames.ReturnModel.Count.ToString(),
                                                 EventName = eventName
                                             },
                                            Success = true
                                        });
                                    }
                                    else
                                    {
                                        this.Connection.Send(e, new UnliQServerResponse<ReserveModel>
                                        {
                                            Model = new ReserveModel
                                            {
                                                CurrentQueueCount = resultUserNames.ReturnModel.Count.ToString(),
                                                EventName = eventName,
                                                QueueNumber = resultQueueNumber.ReturnModel.ToString()
                                            },
                                            Success = true
                                        });
                                    }
                                });
                            }

                        }


                        break;
                    }
            }
        }

        private void UpdateNowService(string connectionId, string eventName)
        {
            var group = GetGroupName(connectionId);

            // _queueService.NextQueue(eventName);
            //var currentQueue = _queueService.GetCurrentQueue(eventName);

            //this.Groups.Send(group, new UnliQServerResponse<string>
            //{
            //    ConnectionId = connectionId,
            //    Type = UPDATE_NOWSERVING,
            //    Model = currentQueue.ReturnModel.ToString(),
            //});
        }

        #endregion

        #region [Constructor(s)]

        public UnliQConnection(IQueueService service, IUserService userService)
        {
            _queueService = service;
            _userService = userService;
        }

        public UnliQConnection()
        {
            _queueService = new QueueService();
            _userService = new UserService();
        }

        #endregion

        #region [PersistentConnection Member(s)]

        protected override Task OnConnectedAsync(IRequest request, string connectionId)
        {
            return ConnectionActivity(connectionId, UnliQConnectType.Connect);
        }

        protected override Task OnDisconnectAsync(string connectionId)
        {
            return ConnectionActivity(connectionId, UnliQConnectType.Disconnect);
        }

        protected override Task OnReceivedAsync(IRequest request, string connectionId, string data)
        {
            DecodeMessage(data, connectionId);
            return base.OnReceivedAsync(request, connectionId, data);
        }

        protected override Task OnErrorAsync(Exception error)
        {
            return base.OnErrorAsync(error);
        }

        #endregion
    }
}